#include "Parser.h"
#include <iostream>
#include <vector>
//#define DEBUG

using namespace LightChart;

InputParser::InputParser() {
    storage = &Storage::get_instance();
}
InputParser::~InputParser() {}
Conversion InputParser::isNumber(const std::string& s)
{
    std::istringstream iss(s);
    double d;
    if(iss >> d)
    {
    	return Conversion(true,d);
    }
    return Conversion(false,0.);
}
bool InputParser::parse(Storage* s, const char* fn, SeriesOrientation so, bool h, bool f, bool l)
{
    file.open(fn);
    if(!file) return false;
    #ifdef DEBUG
    of.open("debug.log"); //only for debugging
    #endif
    bool success = false;
    storage = s;
    seriesOrientation = so;
    containsHeader = h;
    containsFooter = f;
    labels = l;
    from = 0;
    to = -1;
    nrOfSeries = 0;
    try
    {
	success = prepareFile();
    }
    catch(boost::bad_get&)
    {
	success = false;
    }

    #ifdef DEBUG
    of.close();
    #endif
    file.close();
    return success;
}

bool InputParser::prepareFile() throw(boost::bad_get)
{
    std::string line;
    file.seekg(0,std::ios_base::beg);
    if(containsHeader)
    {
	do
	{
	    getline(file,line);
	    from = file.tellg();
	}
	while(!line.empty());
    }
    if(containsFooter)
    {
    	file.seekg(from,std::ios_base::beg);
	do
	{
	    to = file.tellg();
	    getline(file,line);
	}
	while (!line.empty());
    }
    std::stringstream ss;
    std::vector<std::string> label;
    Conversion c;
    int i = 0;
    file.seekg(from,std::ios_base::beg);
    if(seriesOrientation == VERTICAL_SERIES)
    {
    	if(labels)
    	{
	    getline(file,line);
	    from = file.tellg();
	    ss.str(line);
	    while(!ss.eof())
	    {
		ss >> line;
		label.push_back(line);
	    }
	    ss.clear();
    	}
    	getline(file,line);
    	ss.str(line);
    	i = 0;
    	while (!ss.eof())
    	{
	    ss >> line;
	    if(line.empty()) break;
	    if((c = isNumber(line)))
	    {
		if(labels)
		{
		    #ifdef DEBUG
		    of << "create(\"" << label[i] << "\",DOUBLE_PRECISION)\n";
		    #endif
            storage->series.create(label[i],DOUBLE_PRECISION);
		    ++i;
		}
		else
		{
		    #ifdef DEBUG
		    of << "create(\"\",DOUBLE_PRECISION)\n";
		    #endif
            storage->series.create("",DOUBLE_PRECISION);
		}
	    }
	    else
	    {
		if(labels)
		{
		    #ifdef DEBUG
		    of << "create(\"" << label[i] << "\",S_TEXT)\n";
		    #endif
            storage->series.create(label[i],S_TEXT);
		    ++i;
		}
		else
		{
		    #ifdef DEBUG
		    of << "create(\"\",S_TEXT)\n";
		    #endif
            storage->series.create("",S_TEXT);
		}
	    }
	    ++nrOfSeries;
	    line.clear(); //in connection with break condition ensures that any whitespace or enter at the end of the line will not be recognized as a proper value
	}
	
    }
    return readFile();
}
bool InputParser::readFile() throw(boost::bad_get)
{
    file.seekg(from,std::ios_base::beg); //begin after header (if exists)
    std::stringstream ss;
    std::string line;
    Conversion c;
    std::string tmp1,tmp2;
    unsigned id = 0;
    bool success = false;
    if(seriesOrientation == VERTICAL_SERIES)
    {
	while(!file.eof())
	{
	    if(file.tellg() == to) break;
	    getline(file,line);
	    ss.str(line);
	    while (!ss.eof())
	    {
		ss >> line;
		if(line.empty()) break;
		if((c = isNumber(line)))
		{
		    #ifdef DEBUG
		    of << "add(" << id % nrOfSeries << ", " << c.val() << ")\n";
		    #endif
            storage->series[id % nrOfSeries].add(c.val());
		    ++id;
		}
		else
		{
		    #ifdef DEBUG
		    of << "add(" << id % nrOfSeries << ", \"" << line << "\")\n";
		    #endif
            storage->series[id % nrOfSeries].add(line);
		    ++id;
		}
		line.clear();
	    }
	    ss.clear();
	}
    }
    else if(seriesOrientation == HORIZONTAL_SERIES)
    {
	while(!file.eof())
	{
	    if(file.tellg() == to) break;
	    getline(file,line);
	    if(!line.empty())
	    {
		ss.str(line);
		++nrOfSeries;
		if(labels)
		{
		    ss >> tmp1; //contains series label
		}
		ss >> tmp2; //contains first value in series
		if((c = isNumber(tmp2)))
		{
		    if(labels)
		    {
			#ifdef DEBUG
			of << "id = create(\"" << tmp1 << "\",DOUBLE_PRECISION)" << std::endl;
			#endif
            id = storage->series.create(tmp1,DOUBLE_PRECISION);
		    }
		    else
		    {
			#ifdef DEBUG
			of << "id = create(\"\",DOUBLE_PRECISION)" << std::endl;
			#endif
            id = storage->series.create("",DOUBLE_PRECISION);
		    }
		    #ifdef DEBUG
		    of << "add(" << id << ", " << c.val() << ")" << std::endl;
		    #endif
            storage->series[id].add(c.val());
		}
		else //first value in series is not a number
		{
		    if(labels)
		    {
			#ifdef DEBUG
			of << "id = create(\"" << tmp1 << "\",S_TEXT)" << std::endl;
			#endif
            id = storage->series.create(tmp1,S_TEXT);
		    }
		    else
		    {
			#ifdef DEBUG
			of << "id = create(\"\",S_TEXT)" << std::endl;
			#endif
            id = storage->series.create("",S_TEXT);
		    }
		    #ifdef DEBUG
		    of << "add(" << id << ", " << tmp2 << ")" << std::endl;
		    #endif
            storage->series[id].add(tmp2);
		}
		while(!ss.eof())
		{
		    ss >> tmp1;
		    if((c = isNumber(tmp1)))
		    {
			#ifdef DEBUG
			of << "add(" << id << ", " << c.val() << ")" << std::endl;
			#endif
            storage->series[id].add(c.val());
		    }
		    else
		    {
			#ifdef DEBUG
			of << "add(" << id << ", \"" << tmp1 << "\")" << std::endl;
			#endif
            storage->series[id].add(tmp1);
		    }
		}
		ss.clear();
	    }
	}
    }
    success = true;
    return success;
}
#ifdef DEBUG
#undef DEBUG
#endif
